#pragma

#include <iostream>
#include <vector>
#include <pthread.h>

#include "Sem.hpp"

const int g_default_num = 5;

class RingQueue
{
public:
    RingQueue(int default_num = g_default_num)
        : _rq(default_num), 
          _num(default_num),
          c_idx(0),
          p_idx(0),
          space_sem(default_num),
          data_sem(0)
    {
        pthread_mutex_init(&clock, nullptr);
        pthread_mutex_init(&plock, nullptr);
    }
    ~RingQueue()
    {
        pthread_mutex_destroy(&clock);
        pthread_mutex_destroy(&plock);
    }
    void push(const int &data)
    {
        space_sem.p();
        pthread_mutex_lock(&plock);
        _rq[p_idx++]=data;
        p_idx%=_num;
        pthread_mutex_unlock(&plock);
        data_sem.v();
    }
    void pop(int &data)
    {
        data_sem.p();
        pthread_mutex_lock(&clock);
        data=_rq[c_idx++];
        c_idx%=_num;
        pthread_mutex_unlock(&clock);
        space_sem.v();
    }
private:
    std::vector<int> _rq;
    int _num;
    int c_idx;
    int p_idx;
    Sem space_sem;
    Sem data_sem;
    pthread_mutex_t clock;
    pthread_mutex_t plock;
};